﻿/*
 *   TypeOfValue.cs
 *   Copyright (c) 2011 - BitFox Software and Ricardo Federico Villafañes
 *   Contact: federvillaf@hotmail.com
 *   
 *   Licensing: This product is covered by Microsoft Reciprocal License (MS-RL)
 *              see https://bitfoxeval.codeplex.com/license
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using BitFox.Evaluator;
using BitFox.Evaluator.Functions;

namespace WFormSample
{
    /// <summary>
    /// The form used to test (and as usage's sample) for Bitfox's evaluator.
    /// </summary>
    public partial class TestEvaluatorForm : Form
    {
        Evaluator eval = new Evaluator();

        Expression exp = null;

        Tips tips;

        /// <summary>
        /// Form's constructor.
        /// </summary>
        public TestEvaluatorForm()
        {
            InitializeComponent();

            // Link tips
            tips = new Tips(browser);

            // Fill the combo with builtin functions
            Dictionary<string, bool> avoidDupl = new Dictionary<string, bool>();
            foreach (var kvp in BuiltinFunctions.FunctionList)
            {
                string funcName = kvp.Key + "(";
                for (int pNum = 1; pNum <= kvp.Value; pNum++)
                {
                    if (pNum != 1) funcName += ", ";
                    funcName += "p" + pNum;
                }
                cbFuncs.Items.Add(funcName + ")");
            }
        }

        /// <summary>
        /// Set into evaluator the list of variables
        /// </summary>
        /// <returns>true if no errof is found, else, false</returns>
        private bool PrepareVariables()
        {
            eval.Variables.Clear();
            foreach (VariableEntry row in bsVariables)
            {
                string vn = row.Name.Trim().ToUpper();
                if (vn.Length > 0)
                {
                    object val = string.Empty;
                    row.Value = row.Value.Trim();
                    string targetType = row.VarType.Trim().ToLower();
                    try
                    {
                        switch (targetType)
                        {
                            case "integer":
                                val = Convert.ToInt32(row.Value);
                                break;

                            case "datetime":
                                val = DateTime.Parse(row.Value);
                                break;

                            case "logical":
                                val = (row.Value == ".T." || row.Value == ".t.") ? true : false;
                                break;

                            default:
                                val = row.Value;
                                break;
                        }

                        eval.Variables[vn] = val;
                    }
                    catch
                    {
                        MessageBox.Show(string.Format("Variable '{0}' cannot be parsed as '{1}'", vn, targetType), "Error");
                        return false;
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// Compile the expression
        /// </summary>
        /// <returns>true if compilation was ok, else, false.</returns>
        private bool Compile()
        {
            try
            {
                PrepareVariables();
                string exprText = tbExpression.Text.Trim();
                exp = eval.Compile(exprText);
                return true;
            }
            catch (Exception exc)
            {
                tbResult.Text = "(Error compiling the expression)";
                MessageBox.Show(exc.Message, "Error");
                return false;
            }
        }

        /// <summary>
        /// Execute the just compiled expression
        /// </summary>
        /// <param name="displayResult"><b>true</b> if the method must show evaluation's result</param>
        /// <returns><b>true</b> if execution was ok, else, <b>false</b></returns>
        private bool Run(bool displayResult)
        {
            if (exp == null) return false;
            try
            {
                object result = exp.Run();
                if (displayResult)
                    tbResult.Text = Convert.ToString(result);
                return true;
            }
            catch (Exception exc)
            {
                tbResult.Text = "(Error running the expression)";
                MessageBox.Show(exc.Message, "Error");
                return false;
            }
        }

        /// <summary>
        /// Click method for compile button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btCompile_Click(object sender, EventArgs e)
        {
            browser.DocumentText = "<html><font face='Tahoma' size='2'><b>hola</b> muchachos</font></html>";
            if(Compile())
                Run(true);
        }

        /// <summary>
        /// Click method for 'compile once, run 100000 times' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btTestPerformance_Click(object sender, EventArgs e)
        {
            tbResult.Text = string.Empty;
            Application.DoEvents();

            if (Compile())
            {
                var start = DateTime.Now;
                bool ok = true;
                for (int loop = 0; loop < 100000; loop++)
                {
                    ok = Run(false);
                    if (!ok) break;
                }

                if (ok)
                {
                    var elapsed = DateTime.Now.Subtract(start);
                    tbResult.Text = elapsed.ToString();
                }
            }
        }

        /// <summary>
        /// click handler for 'append' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btAppend_Click(object sender, EventArgs e)
        {
            tbExpression.Text = tbExpression.Text.Trim() + " " + cbFuncs.Text;
        }

        /// <summary>
        /// click handler for 'previous tip' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btPrevTip_Click(object sender, EventArgs e)
        {
            tips.PreviousTip();
        }

        /// <summary>
        /// click handler for 'next tip' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btNextTip_Click(object sender, EventArgs e)
        {
            tips.NextTip();
        }
    }
}
